package com.vcc.web.core.queue.batch.recharge.queue;

import com.vcc.channel.base.model.request.CardRechargeDto;
import com.vcc.channel.base.model.response.CardInfoVo;
import com.vcc.channel.base.service.ChannelBaseService;
import com.vcc.core.constant.CardStatusEnum;
import com.vcc.data.entity.CardType;
import com.vcc.data.entity.UserCard;
import com.vcc.data.entity.UserCardWallet;
import com.vcc.data.entity.Wallet;
import com.vcc.service.service.*;
import com.vcc.web.core.queue.batch.recharge.model.RechargeQueueDto;
import jakarta.annotation.Resource;
import lombok.extern.log4j.Log4j2;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Objects;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Executors;

@Log4j2
@Component
public class RechargeQueue implements CommandLineRunner {

    @Resource
    private UserCardService userCardService;
    @Resource
    private TaskLogService taskLogService;
    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private CardTypeService cardTypeService;
    @Resource
    private UserCardWalletService userCardWalletService;
    @Resource
    private CardOrderService cardOrderService;
    @Resource
    private TaskLogInfoService taskLogInfoService;
    @Resource
    private WalletService walletService;


    private volatile DelayQueue<RechargeQueueDto> delayQueue = new DelayQueue<RechargeQueueDto>();


    public void add(Long taskId, Long cardNumberId, Long taskInfoId, BigDecimal amount, String requestId) {
        synchronized (this) {
            RechargeQueueDto rechargeQueueDto = delayQueue.stream().filter(it -> it.getCardNumberId().equals(cardNumberId)).findFirst().orElse(null);
            if (rechargeQueueDto == null) {
                LocalDateTime now = LocalDateTime.now();
                LocalDateTime nowB = now.plusSeconds(5L);
                long betweenMillis = ChronoUnit.MILLIS.between(now, nowB);
                log.info("当前添加的是{},秒{}", cardNumberId, betweenMillis / 1000);
                delayQueue.put(
                        new RechargeQueueDto(
                                cardNumberId,
                                taskId,
                                taskInfoId,
                                amount,
                                requestId,
                                betweenMillis
                        )
                );
            }
        }
    }


    @Override
    public void run(String... args) throws Exception {
        Executors.newSingleThreadExecutor().execute(new Thread(this::excuteThread));
    }

    private void excuteThread() {
        while (true) {
            try {
                processTask(delayQueue.take());
            } catch (InterruptedException e) {
                break;
            }
        }
    }

    /**
     * 内部执行延时任务
     *
     * @param rechargeQueueDto
     */
    private void processTask(RechargeQueueDto rechargeQueueDto) {
        try {
            log.info("当前处理的卡是{}", rechargeQueueDto.getCardNumberId());
            UserCard userCard = userCardService.getByIdOpt(rechargeQueueDto.getCardNumberId()).orElse(null);
            if (userCard == null) {
                taskLogInfoService.completedLogInfo(rechargeQueueDto.getTaskInfoId(), 1, "卡ID:" + rechargeQueueDto.getCardNumberId() + "不存在");
                return;
            }
            if (userCard.getCardStatus().equals(CardStatusEnum.CONTROL.getCode())) {
                taskLogInfoService.completedLogInfo(rechargeQueueDto.getTaskInfoId(), 2, "卡ID:" + rechargeQueueDto.getCardNumberId() + "目前是风控状态状态无法操作");
                return;
            }
            ChannelBaseService channelBaseService = applicationContext.getBean(userCard.getChannelCode(), ChannelBaseService.class);
            CardInfoVo cardInfoVo = channelBaseService.queryCardInfo(userCard.getChannelCardId());
            if (cardInfoVo == null) {
                taskLogInfoService.completedLogInfo(rechargeQueueDto.getTaskInfoId(), 1, "查询卡信息失败");
                return;
            }
            taskLogInfoService.setCardStatus(rechargeQueueDto.getTaskInfoId(), cardInfoVo.getCardStatus(), cardInfoVo.getBalance());
            if (!cardInfoVo.getCardStatus().equals(CardStatusEnum.ACTIVE.getCode())) {
                taskLogInfoService.completedLogInfo(rechargeQueueDto.getTaskInfoId(), 1, "当前卡状态不可充值");
                return;
            }
            CardType card = cardTypeService.getById(userCard.getCardTypeId());
            if (card.getVerifyRechargeCardStatus() != 0) {
                taskLogInfoService.completedLogInfo(rechargeQueueDto.getTaskInfoId(), 1, "当前卡种禁止充值");
                return;
            }
            UserCardWallet userCardWallet = userCardWalletService.findByUserIdAndCardId(userCard.getUserId(), userCard.getCardTypeId());
            if (userCardWallet == null) {
                taskLogInfoService.completedLogInfo(rechargeQueueDto.getTaskInfoId(), 1, "当前卡种钱包未配置");
            }
            Wallet wallet = walletService.getByUserIdAndCurrencyCode(userCard.getUserId(), userCard.getCurrencyCode());
            BigDecimal tempSumRechargeAmount = rechargeQueueDto.getAmount();
            //充值手续费
            if (Objects.equals(userCardWallet.getExchangeRate().compareTo(BigDecimal.valueOf(0)), 1)) {
                BigDecimal tempExchangeRateAmount = userCardWallet.getExchangeRate()
                        .divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP)
                        .multiply(rechargeQueueDto.getAmount())
                        .setScale(2, RoundingMode.HALF_UP);
                if (tempExchangeRateAmount.compareTo(BigDecimal.valueOf(0.01)) < 0) {
                    tempExchangeRateAmount = BigDecimal.valueOf(0.01);
                }
                tempSumRechargeAmount = tempSumRechargeAmount.add(tempExchangeRateAmount);
            }
            if (tempSumRechargeAmount.compareTo(wallet.getUsableQuota()) > 0) {
                taskLogInfoService.completedLogInfo(rechargeQueueDto.getTaskInfoId(), 1, "用户钱包余额不足");
                return;
            }
            //TODO  调用API
            String orderId = rechargeQueueDto.getRequestId();
            walletService.cardRecharge(
                    userCard.getUserId(),
                    userCard.getUserId(),
                    card.getCurrencyCode(),
                    orderId,
                    card.getId(),
                    userCard.getCardNumber(),
                    userCard.getId(),
                    card.getChannelName(),
                    rechargeQueueDto.getAmount(),
                    "批量充值",
                    "CLIENT"
            );
            cardOrderService.rechargeCard(
                    orderId,
                    userCard.getCardTypeId(),
                    userCard.getUserId(),
                    userCard.getUserId(),
                    userCard.getCardNumber(),
                    userCard.getId(),
                    userCard.getChannelCode(),
                    rechargeQueueDto.getAmount(),
                    userCard.getCurrencyCode(),
                    "批量充值",
                    "CLIENT"
            );
            channelBaseService.recharge(
                    CardRechargeDto.builder()
                            .channelCardId(userCard.getChannelCardId())
                            .rechargeAmount(rechargeQueueDto.getAmount())
                            .requestId(orderId)
                            .cardNumberId(userCard.getId())
                            .cardNumber(userCard.getCardNumber())
                            .build()
            );
            taskLogInfoService.completedLogInfo(rechargeQueueDto.getTaskInfoId(), orderId, 0, "充值成功");
        } catch (Exception e) {
            taskLogInfoService.completedLogInfo(rechargeQueueDto.getTaskInfoId(), 1, "充值异常:" + e.getMessage());
            log.error("异常", e);
        } finally {
            Long completeCount = taskLogInfoService.countByTaskIdAndStatus(rechargeQueueDto.getTaskLogId(), 2);
            log.info("当前任务:{},待完成的数量是:{}", rechargeQueueDto.getTaskLogId(), completeCount);
            if (completeCount == 0) {
                taskLogService.processedAccomplish(rechargeQueueDto.getTaskLogId());
            }
        }
    }
}
